// created by noellynch
// May 18, 2011

package com.gruntdb.objects;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class GruntDBFile {
	private		RandomAccessFile		mcl_raFile;
	private		FileChannel				mcl_channel;
	private		File					mcl_theFile;
	
	private		static	ExecutorService		EXECUTOR = Executors.newCachedThreadPool();
	
	public	GruntDBFile(File cl_f) throws Exception {
		mcl_theFile = cl_f;
		
		mcl_raFile = new RandomAccessFile(mcl_theFile, "rwd");
		mcl_channel = mcl_raFile.getChannel();
	}
	
	public	ByteBuffer		getMap(long i_offset, long i_size) throws Exception {
		if(mcl_channel == null) {
			throw new IllegalStateException("File channel is null");
		}
		
		MappedByteBuffer		lcl_buffer = mcl_channel.map(MapMode.READ_WRITE, i_offset, i_size);
		lcl_buffer.load();
		
		return lcl_buffer;
	}
	
	public	Future<ByteBuffer>		getMapAsFuture(final long i_offset, final long i_size) {
		Future<ByteBuffer>		lcl_future = EXECUTOR.submit(new Callable<ByteBuffer>() {
			@Override
			public ByteBuffer call() throws Exception {
				if(mcl_channel == null) {
					throw new IllegalStateException("File channel is null");
				}
				
				MappedByteBuffer		lcl_buffer = mcl_channel.map(MapMode.READ_WRITE, i_offset, i_size);
				lcl_buffer.load();
				
				return lcl_buffer;
			}
		});
		
		return lcl_future;
	}
	
	public	void	allocate(int i_size) throws Exception {
		if(mcl_channel == null) {
			throw new IllegalStateException("File channel is null");
		}
		
		ByteBuffer	lcl_buffer = ByteBuffer.allocateDirect(i_size);
		mcl_channel.write(lcl_buffer, mcl_channel.size());
	}
	
	public	long		size() throws Exception {
		if(mcl_channel == null) {
			throw new IllegalStateException("File channel is null");
		}
		
		return mcl_channel.size();
	}
	
	public	void	writeBytes(String str_value) throws Exception {
		mcl_raFile.writeBytes(str_value);
	}
	
	public	void	close() throws Exception {
		if(mcl_channel != null) {
			mcl_channel.close();
		}
		
		if(mcl_raFile != null) {
			mcl_raFile.close();
		}
	}

	public	GruntDBFileSeek		getASeek() {
		return new GruntDBFileSeek(this);
	}
	
	@Override
	public String toString() {
		return "GruntDBFile [mcl_theFile=" + mcl_theFile + "]";
	}
	
	
}
